Skip to content

fix(worktrees): read the worktree id from .name as well as .worktree_id - #85

Open
thecodedrift wants to merge 2 commits into
mainfrom
fix/worktree-hook-payload
Open

fix(worktrees): read the worktree id from .name as well as .worktree_id#85
thecodedrift wants to merge 2 commits into
mainfrom
fix/worktree-hook-payload

Conversation

@thecodedrift

Copy link
Copy Markdown
Member

Delegating to a background agent with worktree isolation failed outright with WorktreeCreate: no .worktree_id on stdin. Because this hook replaces Claude Code's default creation logic, a non-zero exit means no worktree is created and the agent never starts — so worktree-isolated delegation was simply unavailable.

The payload for that path carries .name (e.g. agent-a5e1de46e730bdfd7) and no .worktree_id at all. That was captured from a real invocation rather than inferred: the hook was temporarily made to dump stdin on failure, the delegation was re-run, and the saved JSON had keys cwd, hook_event_name, name, prompt_id, session_id, transcript_path.

The hook now reads .worktree_id, .worktreeId, or .name, and its contract comment records that the id field is not stable across callers — worth stating, because the previous failure message read as though the harness had sent nothing at all, which sends you looking in the wrong place.

Verified by re-running the delegation against the fixed hook: the worktree was created at worktrees/agent-af8378fb661401c98 and the agent completed its work inside it.

One related thing left alone deliberately: worktree-remove.sh reads .worktree_path, which may be subject to the same drift. It fails open — a missing field just leaves the worktree in place — so the symptom is a stale directory rather than lost work, and I did not want to guess at a fallback that could resolve to something removable. Worth confirming separately against a real remove payload.

@thecodedrift thecodedrift added the skip-changeset PR intentionally ships no release note (bypasses the changeset requirement) label Aug 6, 2026
@thecodedrift
thecodedrift marked this pull request as ready for review August 6, 2026 17:24
Copilot AI lite review requested due to automatic review settings August 6, 2026 17:24
@thecodedrift

Copy link
Copy Markdown
Member Author

@claude /review

@claude

claude Bot commented Aug 6, 2026

Copy link
Copy Markdown

Claude finished @thecodedrift's task in 3m 55s —— View job


Review: fix(worktrees): read the worktree id from .name as well as .worktree_id

  • Gather context (PR diff, changed file, hook contract, related docs)
  • Understand the request (@claude /review — provide review feedback, no implementation)
  • Review diff for correctness, security, performance, clarity
  • Post inline comments on relevant lines
  • Post final top-level assessment

Overall: looks good, low risk, no blocking issues. This is a tightly scoped fix (1 file, +8/-3) to .agents/skills/worktrees-pnpm/scripts/worktree-create.sh.

What it does: widens the worktree_id lookup from .worktree_id only to .worktree_id // .worktreeId // .name, updates the failure message to match, and documents in the contract comment that the id field is not stable across callers (background-agent delegation sends .name, not .worktree_id).

Correctness

  • The jq fallback chain is left-associative and behaves as intended: first non-null/non-false value wins, so a caller sending both .worktree_id and .name still gets .worktree_id (no precedence bug).
  • Whatever value is picked still flows through the existing -z empty check and the regex/.. safety check further down (lines 44–47), so a malformed or unexpected .name fails loudly with a clear error rather than being used unsafely as a path/ref component. Good defense in depth — the new fallback doesn't bypass the existing validation.
  • No other file in the repo references the old error string ("no .worktree_id on stdin"), so nothing else breaks from the message change.
  • Left one inline note: the risk that some other WorktreeCreate caller sends an unrelated .name while genuinely lacking both id fields is real but small-blast-radius (fails the regex check cleanly rather than corrupting state), and it's already flagged in the contract comment — just calling it out explicitly.

Clarity / docs

  • The updated contract comment is a real improvement — it explains why multiple fields are accepted, not just that they are, which is exactly what the previous confusing "no .worktree_id on stdin" failure was missing.
  • Minor nit (inline): the comment rewrite drops .base_path from the list of documented-but-unused stdin fields. Purely cosmetic, but worth a second look in case it was accidental.
  • Not required for this PR, but SKILL.md's verify snippet (.agents/skills/worktrees-pnpm/SKILL.md ~line 108) still only demonstrates probing with .worktree_id; a follow-up could show .name too so the fallback is discoverable without reading the script.

Scope

  • The PR explicitly leaves worktree-remove.sh's .worktree_path field alone, noting it fails open (stale directory, not lost work) rather than guessing at a fallback. That's a reasonable, well-justified boundary for this PR — agreed it shouldn't be bundled in here without a real captured payload to verify against.
  • skip-changeset label is appropriate — this is a dev-tooling hook script fix, not user-facing release content.

No security, performance, or test-adequacy concerns beyond what's noted above. Nice, evidence-based fix (captured from a real failing payload rather than inferred).

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes WorktreeCreate hook robustness by accepting multiple possible worktree identifier fields from stdin, preventing worktree-isolated background-agent delegation from failing when .worktree_id is absent.

Changes:

  • Read the worktree identifier from .worktree_id, .worktreeId, or .name.
  • Improve the failure message when no identifier is present.
  • Expand the hook contract comment to document identifier-field drift across callers.

Comment thread .agents/skills/worktrees-pnpm/scripts/worktree-create.sh Outdated
Comment thread .agents/skills/worktrees-pnpm/scripts/worktree-create.sh Outdated
Comment thread .agents/skills/worktrees-pnpm/scripts/worktree-create.sh
@thecodedrift
thecodedrift force-pushed the fix/worktree-hook-payload branch from ddd74f1 to 93caf41 Compare August 6, 2026 23:59
@thecodedrift

Copy link
Copy Markdown
Member Author

Re: @claude[bot] — "Claude finished @thecodedrift's task in 3m 55s — Review: fix(worktrees): read the worktree id from .name…"
#85 (comment)

All three inline notes are addressed in ddd74f1: the contract comment now names all three spellings, records that .name rests on one captured payload rather than a guaranteed contract, and .base_path is restored to the field list. Took the SKILL.md follow-up too — the verify probe now shows a .name payload, so the fallback is discoverable without reading the script. worktree-remove.sh stays out of scope as described.

— AI Coding Agent

thecodedrift and others added 2 commits August 6, 2026 23:06
Delegating to a background agent with worktree isolation failed outright:
"WorktreeCreate: no .worktree_id on stdin". The hook replaces the default
creation logic, so a non-zero exit means no worktree and no agent.

The payload for that path carries `.name` (e.g. "agent-a5e1de46e730bdfd7") and
no `.worktree_id` at all — captured from a real invocation rather than inferred.
The hook now reads `.worktree_id`, `.worktreeId`, or `.name`, and its contract
comment records that the field is not stable across callers, since the failure
message otherwise reads as though the harness sent nothing.

Verified by re-running the delegation: the worktree was created and the agent
completed its work in it.
The contract comment said "both are read" while the implementation accepts
three (.worktree_id, .worktreeId, .name). Name all three, and write down that
.name rests on one captured payload rather than a guaranteed contract — an
unrelated .name lands on the regex guard below and fails loudly, which is the
intended floor. Restore .base_path to the documented-but-unused field list
(dropped in the rewrite, not deliberately), and show a .name payload in the
SKILL.md verify probe so the fallback is discoverable without reading the
script.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jwc9FFroR3mTZ4hLiSkkX3
@thecodedrift
thecodedrift force-pushed the fix/worktree-hook-payload branch from 93caf41 to 1cb9dc5 Compare August 7, 2026 06:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

skip-changeset PR intentionally ships no release note (bypasses the changeset requirement)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants